package info.peigen.hotpot.component.pay.wechat.service;

import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import info.peigen.hotpot.component.pay.wechat.enums.WechatPayTradeType;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

/**
 * <b>(WechatPayService)</b>
 *
 * @author czj
 * @version 1.0.0
 * @since 2022/8/25
 */
@SuppressWarnings("UnusedReturnValue")
@Slf4j
@Component
public class WechatPayService {
    @Inject
    private WxPayService wxPayService;

    /**
     * 退款
     *
     * @param refundNo  商户退款单号。商户系统内部的退款单号，商户系统内部唯一，同一退款单号多次请求只退一笔
     * @param tradeNo   商户订单号。商户侧传给微信的订单号
     * @param totalFee  订单金额，单位为分
     * @param refundFee 退款金额，单位为分
     *
     * @return WxPayRefundResult
     */
    @SneakyThrows
    public WxPayRefundResult refund(String refundNo, String tradeNo, Integer totalFee, Integer refundFee) {
        if (Solon.cfg().isDebugMode()) {
            log.info("【调试模式】假装调用了微信退款接口");
            return null;
        }
        return wxPayService.refund(
                WxPayRefundRequest.newBuilder()
                        .outRefundNo(refundNo)
                        .outTradeNo(tradeNo)
                        .totalFee(totalFee)
                        .refundFee(refundFee)
                        .build()
        );
    }

    /**
     * 退款
     *
     * @param refundNo  商户退款单号。商户系统内部的退款单号，商户系统内部唯一，同一退款单号多次请求只退一笔
     * @param tradeNo   商户订单号。商户侧传给微信的订单号
     * @param totalFee  订单金额，单位为分
     * @param refundFee 退款金额，单位为分
     *
     * @return WxPayRefundResult
     */
    public WxPayRefundResult refund(String refundNo, String tradeNo, Long totalFee, Long refundFee) {
        return refund(refundNo, tradeNo, Integer.valueOf(totalFee.toString()), Integer.valueOf(refundFee.toString()));
    }

    /**
     * 生成预付单
     *
     * @param businessName   商户名
     * @param outTradeNo     商户订单号
     * @param totalFee       总金额，单位为分，详见支付金额
     * @param openid         openid
     * @param spbillCreateIp 终端IP
     *
     * @return WxPayMpOrderResult
     */
    @SneakyThrows
    public WxPayMpOrderResult createPrePay(String businessName, String outTradeNo, Integer totalFee, String openid, String spbillCreateIp) {
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(businessName);
        orderRequest.setOutTradeNo(outTradeNo);
        orderRequest.setTotalFee(totalFee);
        orderRequest.setOpenid(openid);
        orderRequest.setSpbillCreateIp(spbillCreateIp);
        orderRequest.setTradeType(WechatPayTradeType.JSAPI.getCode());
        orderRequest.setNotifyUrl(wxPayService.getConfig().getNotifyUrl());
        return wxPayService.createOrder(orderRequest);
    }

    /**
     * 支付回调
     *
     * @param xmlData String
     *
     * @return WxPayOrderNotifyResult
     */
    @SneakyThrows
    public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) {
        return wxPayService.parseOrderNotifyResult(xmlData);
    }

    /**
     * 调用统一下单接口，并组装生成支付所需参数对象.
     *
     * @param request 统一下单请求参数
     *
     * @return 返回 {@link com.github.binarywang.wxpay.bean.order}包下的类对象
     */
    public WxPayMpOrderResult createOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
        request.setTradeType(WechatPayTradeType.JSAPI.getCode());
        request.setNotifyUrl(wxPayService.getConfig().getNotifyUrl());
        return wxPayService.createOrder(request);
    }

    /**
     * @param transactionId 微信订单号
     * @param outTradeNo    商户系统内部的订单号，当没提供transactionId时需要传这个
     *
     * @return WxPayOrderQueryResult
     *
     * @throws WxPayException exception
     */
    public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException {
        return wxPayService.queryOrder(transactionId, outTradeNo);
    }
}
